/**
 * Author: Dmitry Ustimov
 * Date: 5/22/13
 * Time: 2:17 PM
 */

package com.gmail.dmitryustimov.ms.java7.visitor.mod_actionmap.work.demo.structure1_3_9;

import com.gmail.dmitryustimov.ms.java7.patternslib.visitor.actionmap.VisitAction;

import java.util.HashMap;
import java.util.Map;

public class ConcreteElementVisitor<T> extends ElementVisitor<T> {

    public <S extends T> ConcreteElementVisitor() {
        Map<Class<? extends T>, VisitAction<? extends T>> actions = new HashMap<>();
        actions.put((Class<S>)ElementRoot.class, (VisitAction<S>)this.new ElementRootVisitor());
        actions.put((Class<S>)ElementA.class,    (VisitAction<S>)this.new ElementAVisitor());
        actions.put((Class<S>)ElementB.class,    (VisitAction<S>)this.new ElementBVisitor());
        actions.put((Class<S>)ElementC.class,    (VisitAction<S>)this.new ElementCVisitor());
        actions.put((Class<S>)ElementA1.class,   (VisitAction<S>)this.new ElementA1Visitor());
        actions.put((Class<S>)ElementB1.class,   (VisitAction<S>)this.new ElementB1Visitor());
        actions.put((Class<S>)ElementC1.class,   (VisitAction<S>)this.new ElementC1Visitor());
        actions.put((Class<S>)ElementA2.class,   (VisitAction<S>)this.new ElementA2Visitor());
        actions.put((Class<S>)ElementB2.class,   (VisitAction<S>)this.new ElementB2Visitor());
        actions.put((Class<S>)ElementC2.class,   (VisitAction<S>)this.new ElementC2Visitor());
        actions.put((Class<S>)ElementA3.class,   (VisitAction<S>)this.new ElementA3Visitor());
        actions.put((Class<S>)ElementB3.class,   (VisitAction<S>)this.new ElementB3Visitor());
        actions.put((Class<S>)ElementC3.class,   (VisitAction<S>)this.new ElementC3Visitor());
        init(actions);
    }

    private void printElement(Element element) {
    }

    public class ElementRootVisitor implements VisitAction<ElementRoot> {
        @Override
        public void visit(ElementRoot element) {
            printElement(element);
            visitElements(element, ConcreteElementVisitor.this);
        }
    }

    public class ElementAVisitor implements VisitAction<ElementA> {
        @Override
        public void visit(ElementA element) {
            printElement(element);
            visitElements(element, ConcreteElementVisitor.this);
        }
    }

    public class ElementBVisitor implements VisitAction<ElementB> {
        @Override
        public void visit(ElementB element) {
            printElement(element);
            visitElements(element, ConcreteElementVisitor.this);
        }
    }

    public class ElementCVisitor implements VisitAction<ElementC> {
        @Override
        public void visit(ElementC element) {
            printElement(element);
            visitElements(element, ConcreteElementVisitor.this);
        }
    }

    public class ElementA1Visitor implements VisitAction<ElementA1> {
        @Override
        public void visit(ElementA1 element) {
            printElement(element);
        }
    }

    public class ElementB1Visitor implements VisitAction<ElementB1> {
        @Override
        public void visit(ElementB1 element) {
            printElement(element);
        }
    }

    public class ElementC1Visitor implements VisitAction<ElementC1> {
        @Override
        public void visit(ElementC1 element) {
            printElement(element);
        }
    }

    public class ElementA2Visitor implements VisitAction<ElementA2> {
        @Override
        public void visit(ElementA2 element) {
            printElement(element);
        }
    }

    public class ElementB2Visitor implements VisitAction<ElementB2> {
        @Override
        public void visit(ElementB2 element) {
            printElement(element);
        }
    }

    public class ElementC2Visitor implements VisitAction<ElementC2> {
        @Override
        public void visit(ElementC2 element) {
            printElement(element);
        }
    }

    public class ElementA3Visitor implements VisitAction<ElementA3> {
        @Override
        public void visit(ElementA3 element) {
            printElement(element);
        }
    }

    public class ElementB3Visitor implements VisitAction<ElementB3> {
        @Override
        public void visit(ElementB3 element) {
            printElement(element);
        }
    }

    public class ElementC3Visitor implements VisitAction<ElementC3> {
        @Override
        public void visit(ElementC3 element) {
            printElement(element);
        }
    }
}
